package com.ms.game.bank;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ms.game.bank.container.BankInfoBin;
import com.ms.game.bank.db.BankDAO;
import com.ms.game.bank.db.BankLogModel;
import com.ms.game.bank.db.CashLogModel;
import com.ms.game.bank.db.VipLogModel;
import com.ms.game.common.container.LevelInfoBin;
import com.ms.game.common.container.LevelInfoBinUtil;
import com.ms.game.common.container.LevelUpInfo;
import com.ms.game.purchase.bin.PurchaseType;
import com.ms.game.rebate.RebateModifyStatus;
import com.ms.game.rebate.RebateType;
import com.ms.game.rebate.db.RebateLogModel;
import com.ms.player.Player;
import com.ms.player.PlayerAttributeType;
import com.ms.player.UpdateAttributeList;
import com.ms.player.message.SUpdatePlayerZoneDataByAttributeList;
import com.ms.service.error.ErrorCode;
import com.ms.service.module.account.message.SAccountCashBonusMessage;
import com.xpec.c4.db.dao.PlayerDAO;
import com.xpec.c4.db.dao.PlayerLevelCalculator;
import com.xpec.c4.game.time.TimeConstants;
import com.xpec.c4.game.time.TimeSys;
import com.xpec.c4.game.utility.GUID;
import com.xpec.c4.game.utility.GameUtility;
import com.xpec.c4.message.MessageTypes;
import com.xpec.c4.service.group.transportlayer.GroupMessage;
import com.xpec.c4.service.message.MessageAction;
import com.xpec.c4.service.module.common.PlayerCommonInfoManager;

public class BuyFeeProcessor {
	private static Log log = LogFactory.getLog(BuyFeeProcessor.class);
	
	/**
	 * 包月天數(30天)
	 */
	private static final long BUY_MONTHLY_FEE_DAYS = 30 * TimeConstants.MILLI_SECOND_PRE_DAY;

	/**
	 * 包周天數(7天)
	 */
	private static final long BUY_WEEKLY_FEE_DAYS = 7 * TimeConstants.MILLI_SECOND_PRE_DAY;
	
	/**
	 * 包月上限月份 
	 * (上限12個月)
	 */
	public static final long MONTHLY_FEE_MAX_MONTH = 12 * 30 * TimeConstants.MILLI_SECOND_PRE_DAY;
	
	/**
	 * 包週上限週數
	 * (48週)
	 */
	public static final long WEEKLY_FEE_MAX_WEEK = 48 * TimeConstants.MILLI_SECOND_PER_WEEK;
	
	public static int checkCanBuyFee(Player player, int purchaseType){
		long feeEndTime = 0l;
		long buyFeePerTime = 0;
		long buyFeeLimitTime = 0l;

		if (purchaseType == PurchaseType.MONTH) {
			// 包月
			feeEndTime = player.getMonthlyFeeEndTime();
			buyFeePerTime = BUY_MONTHLY_FEE_DAYS;
			buyFeeLimitTime = MONTHLY_FEE_MAX_MONTH;
		}

		if (purchaseType == PurchaseType.WEEK) {
			// 包周
			feeEndTime = player.getWeeklyFeeEndTime();
			buyFeePerTime = BUY_WEEKLY_FEE_DAYS;
			buyFeeLimitTime = WEEKLY_FEE_MAX_WEEK;
		}

		if (feeEndTime + buyFeePerTime > TimeSys.currentTimeMills() + buyFeeLimitTime) {
			if (purchaseType == PurchaseType.MONTH) {
				return ErrorCode.MONTHLY_FEE_TOTAL_DAY_OVERFLOW;
			}

			if (purchaseType == PurchaseType.WEEK) {
				return ErrorCode.WEEKLY_TOTAL_OVERFLOW;
			}
		}

		return ErrorCode.SUCCESS;
	}
	
	public static int buyFee(String orderId, Player player, ArrayList<GUID> accountPlayers, int purchaseType, int addVipExp) {
		GUID sessionId = PlayerCommonInfoManager.getInstance().getSessionByPlayerGuid(player.getGuid());
		String playerZone = PlayerCommonInfoManager.getInstance().getPlayerZoneId(player.getGuid());
		boolean isFirstStorePlayer = !player.isHaveFirstStoreCharacter();
		
		String playerId = player.getGuid().toString();
		String playerName = player.getNameWithNumber();
		String accountId = player.getAccountId().toString();
		
		
		// 包X所需CASH
		long buyFeeCash = BankInfoBin.getInstance().getFeeInfos().get(purchaseType).getFee();
		// 包X當下配發
		long buyFeeFirstPay = BankInfoBin.getInstance().getFeeInfos().get(purchaseType).getFeeFirstPay();
		BigDecimal bankGoldChangeValue = new BigDecimal(buyFeeFirstPay);
		
		Object[] cashOb = BankDAO.loadAccountCashPoint(player.getAccountId());
		if (cashOb == null) {
			return ErrorCode.DB_OPERATION_FAIL;
		}

		long beforeAccountCash = (Long)cashOb[0];
		if (isFirstStorePlayer) {
			isFirstStorePlayer = !(boolean) cashOb[1];
		}
		
		long afterAccountCash = beforeAccountCash - buyFeeCash;
		if (afterAccountCash < 0) {
			//點數不足
			if(log.isErrorEnabled()) {
				log.error("player " + playerId + " cash is " + beforeAccountCash + " cash not enough,purchase type :" + purchaseType);
			}
			return ErrorCode.CASH_POINT_NOT_ENOUGH;
		}
		
		boolean isSave = false;
		GameUtility.writeCashUpdateConsoleLog("updateAccountCashDCLAsysn.asyncExecute()", accountId, beforeAccountCash, buyFeeFirstPay, afterAccountCash);
		isSave = BankDAO.UpdateAccountCashPoint(GUID.parseUUID(accountId), afterAccountCash, isFirstStorePlayer);	
		if(!isSave) {
			GameUtility.writeCashUpdateConsoleLog("updateAccountCashDCLAsysn.asyncExecute() DB Operation Fail", accountId, beforeAccountCash, buyFeeFirstPay, afterAccountCash);
			return ErrorCode.DB_OPERATION_FAIL;
		}
		
		BigDecimal bankGoldBeforeChange = player.getBankGoldCoin();
			
		// 更新玩家包月時間
		BankDAO.updateFeeInfo(player, purchaseType);

		// 把包月當下配發的錢加到bank
		BigDecimal bankGoldAfterChange = BankDAO.UpdateBankMoney(player.getGuid(), bankGoldChangeValue);
		player.setBankGoldCoin(bankGoldAfterChange);
		
		CashChangeWay cashChangeWay = null;
		BankMoneyChangeWay bankMoneyChangeWay = null;
		RebateType rebateType = null;
		if (purchaseType == PurchaseType.MONTH) {
			cashChangeWay = CashChangeWay.SUB_MONTHLY_FEE_PAY;
			bankMoneyChangeWay = BankMoneyChangeWay.ADD_MONTHLY_FEE_FIRST_PAY;
			rebateType = RebateType.MONTHLY_FEE_FIREST_PAY;
		} else if (purchaseType == PurchaseType.WEEK) {
			cashChangeWay = CashChangeWay.SUB_WEEKLY_FEE_PAY;
			bankMoneyChangeWay = BankMoneyChangeWay.ADD_WEEKLY_FEE_FIRST_PAY;
			rebateType = RebateType.WEEKLY_FEE_FIREST_PAY;
		}
		
		// cashlog 做個紀錄
		CashLogModel cashLogModel = new CashLogModel();
		cashLogModel.setOrderId(orderId);
		cashLogModel.setAccountId(accountId);
		cashLogModel.setPlayerId(playerId);
		cashLogModel.setPlayerName(playerName);
		cashLogModel.setCashBeforeChange(beforeAccountCash);
		cashLogModel.setCashChangeValue(buyFeeCash);
		cashLogModel.setCashAfterChange(afterAccountCash);
		cashLogModel.setGoldBeforeChange(player.getGoldCoin());
		cashLogModel.setGoldChangeValue(BigDecimal.ZERO);
		cashLogModel.setGoldAfterChange(player.getGoldCoin());
		cashLogModel.setChangeWay(cashChangeWay.getId());
		cashLogModel.setChangeWayDesc(cashChangeWay.getDesc());
		BankDAO.saveLog(cashLogModel);
		
		BigDecimal bonusValue = cashLogModel.getBonusAfterChange() == null ? BigDecimal.ZERO : cashLogModel.getBonusChangeValue();

		SAccountCashBonusMessage msg = new SAccountCashBonusMessage();
		msg.cashValue = cashLogModel.getCashAfterChange();
		msg.bonusValue = bonusValue.toString();
		
		for (GUID guid : accountPlayers) {
			GUID sid = PlayerCommonInfoManager.getInstance().getSessionByPlayerGuid(guid);
			if (sid == null)
				continue;
			MessageAction.sendMessage(sessionId, MessageTypes.S_UPDATE_RECHARGE_CASH_BONUS_RESPONSE, msg);
		}
		
		// 寫bank log
		BankLogModel bankLogModel = new BankLogModel();
		bankLogModel.setOrderId(orderId);
		bankLogModel.setAccountId(player.getAccountId().toString());
		bankLogModel.setPlayerId(playerId);
		bankLogModel.setPlayerName(playerName);
		bankLogModel.setChangeWay(bankMoneyChangeWay.getId());
		bankLogModel.setChangeWayDesc(bankMoneyChangeWay.getDesc());
		bankLogModel.setBankGoldAfterChange(bankGoldAfterChange);
		bankLogModel.setBankGoldChangeValue(bankGoldChangeValue);
		bankLogModel.setBankGoldBeforeChange(bankGoldBeforeChange);
		BankDAO.saveLog(bankLogModel);
		
		// 回饋金
		RebateLogModel rebateLogModel = new RebateLogModel();
		rebateLogModel.setOrderId(orderId);
		rebateLogModel.setBelongsDate(GameUtility.getCurrentDate());
		rebateLogModel.setStatus(RebateModifyStatus.HAVE_RECEIVED);
		rebateLogModel.setTotalRebateCoin(bankGoldChangeValue);
		rebateLogModel.setPlayerId(playerId);
		rebateLogModel.setType(rebateType.getId());
		rebateLogModel.setTypeDesc(rebateType.getDesc());
		rebateLogModel.setPlayerName(playerName);
		BankDAO.saveLog(rebateLogModel);	
		
		// player VIP經驗值
		ArrayList<LevelUpInfo> levelInfo = LevelInfoBin.getInstance().getVipLevelUpInfoList();

		VipChangeWay vipChangeWay = null;
		if (purchaseType == PurchaseType.MONTH) {
			vipChangeWay = VipChangeWay.ADD_MONTHLY_FEE_PAY;
		} else if (purchaseType == PurchaseType.WEEK) {
			vipChangeWay = VipChangeWay.ADD_WEEKLY_FEE_PAY;
		}
		
		// 改變前
		int beforeVipLv = player.getVip();
		long beforeVipExp = player.getVipExp();
		if (beforeVipLv < levelInfo.size()) {
			// Vip未滿才檢查
			player.setVipExp(beforeVipExp + addVipExp);
			for (int index = 0; index < levelInfo.size(); index++) {
				LevelUpInfo info = levelInfo.get(index);
				if (info.getNeedExp() > player.getVipExp()) {
					player.setVip(info.getLevel() - 1);
					break;
				}
				// 最高等級vip
				if (info.getLevel() == levelInfo.size() + 1) {
					player.setVip(info.getLevel());
				}
			}

			VipLogModel vipLogModel = new VipLogModel();
			vipLogModel.setOrderId(orderId);
			vipLogModel.setAccountId(accountId);
			vipLogModel.setPlayerId(playerId);
			vipLogModel.setPlayerName(playerName);
			vipLogModel.setUserType(player.getUserType());
			vipLogModel.setVipBefore(beforeVipLv);
			vipLogModel.setVipAfter(player.getVip());
			vipLogModel.setExpBeforeChange(beforeVipExp);
			vipLogModel.setExpChangeValue(addVipExp);
			vipLogModel.setExpAfterChange(player.getVipExp());
			vipLogModel.setChangeWay(vipChangeWay.getId());
			vipLogModel.setChangeWayDesc(vipChangeWay.getDesc());
			BankDAO.saveLog(vipLogModel);
		}
		
		int afterVip = player.getVip();
		long afterVipExp = player.getVipExp();
		
		
		UpdateAttributeList updateAttributeList = new UpdateAttributeList();
		//第一次轉點的時候，要把角色等級也升到一
		if(beforeVipLv == 0 && afterVip > 0 && player.getLevel() == 0){
			BigDecimal exp = LevelInfoBinUtil.getExpByLevel(0, 1);
		 	player.setExp(exp);
		 	player.setLevel(1);
		 	
			updateAttributeList.addUpdateValue(PlayerAttributeType.LEVEL, 1);
			updateAttributeList.addUpdateValue(PlayerAttributeType.EXP, exp);
			
			HashMap<String, Long> expInfos = LevelInfoBinUtil.getExpInfos(exp);
			updateAttributeList.addUpdateValue(PlayerAttributeType.EXP_IN_CURRENT_LEVEL, expInfos.get(PlayerLevelCalculator.EXP_IN_CURRENT_LEVEL));
			updateAttributeList.addUpdateValue(PlayerAttributeType.EXP_TO_NEXT_LEVEL, expInfos.get(PlayerLevelCalculator.EXP_TO_NEXT_LEVEL));
		}

		// 更新到zone
		updateAttributeList.addUpdateValue(PlayerAttributeType.VIP, afterVip);
		updateAttributeList.addUpdateValue(PlayerAttributeType.VIP_EXP, afterVipExp);
		updateAttributeList.addUpdateValue(PlayerAttributeType.BANK_GOLD_COIN, player.getBankGoldCoin());
		
		
		if(purchaseType == PurchaseType.MONTH) {
			updateAttributeList.addUpdateValue(PlayerAttributeType.MONTHLY_FEE_END_TIME, player.getMonthlyFeeEndTime());
			updateAttributeList.addUpdateValue(PlayerAttributeType.MONTHLY_AWARD_TIME, player.getMonthlyAwardTime());
		} else if(purchaseType == PurchaseType.WEEK){
			updateAttributeList.addUpdateValue(PlayerAttributeType.WEEKLY_FEE_END_TIME, player.getWeeklyFeeEndTime());
			updateAttributeList.addUpdateValue(PlayerAttributeType.WEEKLY_AWARD_TIME, player.getWeeklyAwardTime());
		}
		
		
		if (isFirstStorePlayer){
			updateAttributeList.addUpdateValue(PlayerAttributeType.STORE_REWARD_CONTINUOUS_LOGIN_COUNT, 1);
		}
			
		// 寫到db
		PlayerDAO.updatePlayerFromAttrList(playerId, updateAttributeList.getUpdateList(), player.getUserType());
		
		// 送去 player 所在的 zone 更新
		if(GameUtility.isHaveString(playerZone)){
			SUpdatePlayerZoneDataByAttributeList attMsg = new SUpdatePlayerZoneDataByAttributeList();
			attMsg.setUpdatedAttrList(updateAttributeList.getUpdateList());
			attMsg.setPlayerSessionId(sessionId);
			attMsg.setPlayerId(player.getGuid());

			GroupMessage message = new GroupMessage();
			message.setMessageType(MessageTypes.S_ZONE_UPDATE_PLAYER_ATTRIBUTE_DATA);
			message.setMessageContent(attMsg);
			message.setDestModuleID(playerZone);
			MessageAction.sendGroupMessage(message);
		}
		
		//送給client
		updateAttributeList.sendToClient(player.getGuid(), sessionId, player.getUserType());
		
		return ErrorCode.SUCCESS;
	}
}
